﻿using CRL.Core;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace CRL.Data
{
    public class SQLTrack
    {
        private static ConcurrentDictionary<string, Dictionary<int, SqlInfo>> allSqlCache = new ConcurrentDictionary<string, Dictionary<int, SqlInfo>>();

        #region SqlInfo

        [Serializable]
        public class SqlInfo
        {
            public DateTime Date { get; set; }

            /// <summary>
            /// sql
            /// </summary>
            public string SQL
            {
                get; set;
            }

            /// <summary>
            /// ms
            /// </summary>
            public long MaxElTime
            {
                get
                {
                    return times.OrderByDescending(b => b).Skip(1).FirstOrDefault();
                }
            }

            public long AvgElTime
            {
                get
                {
                    var arry = times.OrderByDescending(b => b).Skip(1);
                    var sum = arry.Sum(b => b);
                    if (sum == 0)
                    {
                        return 0;
                    }
                    return sum / arry.Count();
                }
            }

            //internal long SecondElTime;
            internal List<long> times = new List<long>();

            public int MaxRowCount
            {
                get; set;
            }

            public int DayCount
            {
                get; set;
            }
        }

        #endregion SqlInfo

        public static void SetSQLTrackContext(string pathName)
        {
            CallContext.SetData(Base.ContextPathName, pathName);
        }

        public static ConcurrentDictionary<string, Dictionary<int, SqlInfo>> GetAllSqlSQLTrack()
        {
            return allSqlCache;
        }

        private static Dictionary<int, SqlInfo> GetSQLTrackInfo(out bool useContext)
        {
            var list = new Dictionary<int, SqlInfo>();
            string key = CallContext.GetData<string>(Base.ContextPathName);
            if (string.IsNullOrEmpty(key))
            {
                useContext = false;
                return list;
            }
            var a = allSqlCache.TryGetValue(key, out list);
            if (list == null)
            {
                list = new Dictionary<int, SqlInfo>();
                allSqlCache.TryAdd(key, list);
            }
            useContext = true;
            return list;
        }

        private static object lockObj = new object();

        internal static void SaveSQLElapsedTime(string sql, long elMs, int rowCount = 1)
        {
            if (!SettingConfig.LogSql)
            {
                return;
            }
            if (sql.Contains(" IN ("))
            {
                var regex = new Regex(@" IN \(.+?\)", RegexOptions.IgnoreCase);
                sql = regex.Replace(sql, " IN(ARGS)");
            }
            var dic = GetSQLTrackInfo(out var useContext);
            if (!useContext)
            {
                return;
            }
            SqlInfo item;
            var hash = sql.GetHashCode();
            var a = dic.TryGetValue(hash, out item);
            lock (lockObj)
            {
                if (a)
                {
                    if (DateTime.Now.Date > item.Date.Date)
                    {
                        item.Date = DateTime.Now.Date;
                        item.DayCount = 0;
                        item.times.Clear();
                    }
                    if (item.times.Count() > 100)
                    {
                        item.times.RemoveAt(0);
                    }
                    item.times.Add(elMs);
                    if (item.MaxRowCount < rowCount)
                    {
                        item.MaxRowCount = rowCount;
                    }
                    item.DayCount += 1;
                }
                else
                {
                    dic.Add(hash, new SqlInfo()
                    {
                        SQL = sql,
                        MaxRowCount = rowCount,
                        DayCount = 1,
                        Date = DateTime.Now.Date,
                        times = new List<long> { elMs }
                    });
                }
            }
        }
    }
}